#include <common.h>
#include <environment.h>

struct env_common_func_t {
	int (*saveenv)(void);
	int (*env_relocate_spec)(void);
	char *env_name_spec;
};

#ifdef CONFIG_ENV_IS_IN_NAND
extern int nand_saveenv(void);
extern int nand_env_relocate_spec(void);

static struct env_common_func_t nand_env_cmn_func = {
	.saveenv = nand_saveenv,
	.env_relocate_spec = nand_env_relocate_spec,
	.env_name_spec = "SPINAND",
};

#else
static struct env_common_func_t nand_env_cmn_func = {0};

#endif /* CONFIG_ENV_IS_IN_NAND */

#ifdef CONFIG_ENV_IS_IN_SPI_FLASH
extern int sf_saveenv(void);
extern int sf_env_relocate_spec(void);

static struct env_common_func_t sf_env_cmn_func = {
	.saveenv = sf_saveenv,
	.env_relocate_spec = sf_env_relocate_spec,
	.env_name_spec = "SPI Flash",
};
#else
static struct env_common_func_t sf_env_cmn_func = {0};

#endif /* CONFIG_ENV_IS_IN_SPI_FLASH */

#ifdef CONFIG_ENV_IS_IN_MMC
extern int emmc_saveenv(void);
extern int emmc_env_relocate_spec(void);

static struct env_common_func_t emmc_env_cmn_func = {
	.saveenv = emmc_saveenv,
	.env_relocate_spec = emmc_env_relocate_spec,
	.env_name_spec = "MMC",
};
#else
static struct env_common_func_t emmc_env_cmn_func = {0};

#endif /* CONFIG_ENV_IS_IN_EMMC_FLASH */

char *env_name_spec;
env_t *env_ptr;
struct env_common_func_t *env_cmn_func = NULL;

__attribute__((weak)) int get_boot_media(void)
{
#ifdef CONFIG_SPI_FLASH
	return FH_NOR_FLASH;
#else
    return FH_NAND_FLASH;
#endif
}

int saveenv(void)
{
	return env_cmn_func ? env_cmn_func->saveenv() : -1;
}
#if 0
#if !defined(ENV_IS_EMBEDDED)
static void use_default(void)
{
	puts ("*** Warning - bad CRC, using default environment\n\n");
	set_default_env();
}
#endif
#endif
int g_fh_boot_media_csn = 0;

void env_relocate_spec(void)
{

	switch (get_boot_media()) {
	case FH_NAND_FLASH:
		g_fh_boot_media_csn = 0;
		env_cmn_func = &nand_env_cmn_func;
		break;
	case FH_NOR_FLASH:
		g_fh_boot_media_csn = 0;
		env_cmn_func = &sf_env_cmn_func;
		break;
	case FH_SD0_EMMC_FLASH:
	case FH_SD1_EMMC_FLASH:
		env_cmn_func = &emmc_env_cmn_func;
		break;
	case FH_NOR_FLASH_CS1:
		g_fh_boot_media_csn = 1;
		env_cmn_func = &sf_env_cmn_func;
		break;
	case FH_NAND_FLASH_CS1:
		g_fh_boot_media_csn = 1;
		env_cmn_func = &nand_env_cmn_func;
		break;
	default:
		printf("get env_cmn_func fail\n");
		env_cmn_func = NULL;
		break;
	}

	if (env_cmn_func && !env_cmn_func->env_name_spec)
		env_cmn_func = NULL;

	/* unknow start media */
	if (!env_cmn_func || !env_cmn_func->env_relocate_spec) {
		set_default_env("!no available ENV");
		return;
	}

	env_name_spec = env_cmn_func->env_name_spec;

	env_cmn_func->env_relocate_spec();
	/*if (ret == 0)
			debug("Load env from %s\n", &env_name_spec);
	    else
		use_default();
	*/	
	return;
}

DECLARE_GLOBAL_DATA_PTR;

int env_init(void)
{
	/* Device isn't usable before relocation */
	gd->env_addr = (ulong)&default_environment[0];
	gd->env_valid = 1;

	return 0;
}

